using System;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Windows.Forms;

namespace Camalon.Drawing
{
	/// <summary>
	/// Summary description for ShapeControl.
	/// </summary>
//	[ToolboxItem( true )]
	[ToolboxBitmap( typeof( ShapeControl ), "Components.ShapeControl.bmp")]
    [Designer("Camalon.Drawing.Design.ShapeProviderDesigner, Camalon.Drawing.Design", typeof(IDesigner))]
    public class ShapeControl : Control, ISupportInitialize, IShapeProvider
	{

		#region Events

		[Category("Layout")]
		public event EventHandler				ScalingResizeChanged;

		[Category("Shape")]
		public event ValueChangeEventHandler	ShapeChanged;


		#endregion Events

		private ShapeContainer _shapeContainer ;


		public ShapeControl()
		{
			try
			{
			
				// This call is required by the Windows.Forms Form Designer.

				this.SetStyle( ControlStyles.SupportsTransparentBackColor, true);
				this.SetStyle( ControlStyles.UserPaint, true);
				this.SetStyle( ControlStyles.DoubleBuffer,true);
				this.SetStyle( ControlStyles.ResizeRedraw,true);
				this.SetStyle( ControlStyles.AllPaintingInWmPaint,true);
				this.BackColor = Color.White;

				_shapeContainer = new ShapeContainer( new Rectangle( Point.Empty, new Size(400,300)));
				_shapeContainer.PaintChildsOnly = true;
				_shapeContainer.Status = 2;
				_shapeContainer.ShapeInternalChanged+=new EventHandler(ShapeContainer_ShapeInternalChanged);
				_shapeContainer.ShapePathBoundsChanged+=new ValueChangeEventHandler(ShapeContainer_ShapePathBoundsChanged);
				this.Size = new Size( 400, 300 );
			}
			catch( Exception ex)
			{
				FileWatcher.WriteLine( ex.StackTrace);
			}

		}



		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if( _shape != null) 
				{
//					ShapeContainer sc = _shape as ShapeContainer;
//					if( sc != null)
//					{
//						sc.ScalingResizeChanged-=new EventHandler(Shape_ScalingResizeChanged);
//						sc.ClipChanged+=new EventHandler(Shape_ClipChanged);
//					}
					_shape.ParentChanged-=new ValueChangeEventHandler(Shape_ParentChanged);

				}

				Delegate.RemoveAll(ShapeChanged,ShapeChanged);					ShapeChanged			= null;
				Delegate.RemoveAll(ScalingResizeChanged,ScalingResizeChanged);	ScalingResizeChanged	= null;

				_shapeContainer.ShapeInternalChanged-=new EventHandler(ShapeContainer_ShapeInternalChanged);
				_shapeContainer.ShapePathBoundsChanged-=new ValueChangeEventHandler(ShapeContainer_ShapePathBoundsChanged);
				
				_shapeContainer.Dispose();


			}
			base.Dispose( disposing );
		}





		#region ISupportInitialize Members


		public void BeginInit()
		{
				_shapeContainer.BeginInit();
		}

		public void EndInit()
		{

				_shapeContainer.EndInit();
				_shapeContainer.Bounds = this.ClientRectangle;
		}

		#endregion


		#region Event Handlers
		protected virtual void OnScalingResizeChanged(EventArgs eventArg)
		{
			if( this.ScalingResizeChanged != null) this.ScalingResizeChanged( this, eventArg );
		}

		protected void OnShapeChanged( ValueChangeEventArgs e)
		{
			if( this.ShapeChanged != null) this.ShapeChanged( this, e );	

		}

		#endregion Event Handlers

		private void Shape_ParentChanged(object sender, ValueChangeEventArgs e)
		{
			if( this.Shape == null) return;

			if( this.Shape.Parent != _shapeContainer) this.Shape = null;
		}

//		private void Shape_ScalingResizeChanged(object sender, EventArgs e)
//		{
//			if( this.Shape == null) return;
//
//			ShapeContainer sc = this.Shape as ShapeContainer;
//			if( sc != null && sc.ScalingResize)
//			{
//				if( this.ScalingResize)
//				{
//					this.ScalingResize = false;
//				}
//
//				sc.Anchor = AnchorStyles.Top|AnchorStyles.Left|AnchorStyles.Right|AnchorStyles.Bottom;
//			}
//
//		}
//
//		private void Shape_ClipChanged(object sender, EventArgs e)
//		{
//
//		}

		#region IShapeProvider Members

		//Methods aldready in the control implemented
		//---------------------------------------------------------------
		//		public Size Size
		//		public event System.Windows.Forms.PaintEventHandler Paint;
		//		public void Invalidate()
		//      public Point PointToClient( Point point)


		private Shape _shape;
		[Category( "Shape")] 
		[DefaultValue( null)]
		[Browsable( true)]
		public Shape Shape
		{
			get
			{
				return _shape;
			}
			set
			{
				try
				{
//					if( value == null) 
//						FileWatcher.WriteLine(TypeDescriptor.GetComponentName( this) + "::Shape removing.");

					if( value == _shape) return;

					Shape oldShape = _shape;//Save old Shape for change event


					if( _shape != null) 
					{		
//						ShapeContainer sc = _shape as ShapeContainer;
//						if( sc != null) 
//						{
//							sc.ScalingResizeChanged-=new EventHandler(Shape_ScalingResizeChanged);
//							sc.ClipChanged-=new EventHandler(Shape_ClipChanged);
//						}

						_shape.ParentChanged-=new ValueChangeEventHandler(Shape_ParentChanged);
						_shapeContainer.Shapes.Remove( _shape );
					}
					
					_shape = value;

					if( _shape != null) 
					{
						_shapeContainer.Shapes.Add( _shape );
						_shape.ParentChanged+=new ValueChangeEventHandler(Shape_ParentChanged);
						
//						ShapeContainer sc = _shape as ShapeContainer;
//						if( sc != null) 
//						{
//							sc.ScalingResizeChanged+=new EventHandler(Shape_ScalingResizeChanged);
//							sc.ClipChanged+=new EventHandler(Shape_ClipChanged);
//						}
					}
				
					RefreshRegion();
					this.OnShapeChanged( new ValueChangeEventArgs( oldShape, _shape ));
					this.Invalidate(false);

//					if( _shape == null) 
//						FileWatcher.WriteLine(TypeDescriptor.GetComponentName( this) + "::Shape removed 3.");

				}
				catch( Exception ex)
				{
					FileWatcher.WriteLine( ex.StackTrace);
				}

			}
		}

		void Camalon.Drawing.IShapeProvider.Invalidate()
		{
			this.Invalidate( false);
		}

		#endregion

		protected bool ShouldSerializeScalingResizeBase()
		{
			try
			{
				return _shapeContainer.ScalingResize; 
			}
			catch( Exception ex)
			{
				FileWatcher.WriteLine( ex.StackTrace);
				return false;
			}
		}

		[Category("Shape")]
		[Browsable( false)]
		public Size ScalingResizeBase
		{
			get{ return  _shapeContainer.ScalingResizeBase;}
			set
			{
				if( _shapeContainer.ScalingResizeBase == value) return;

				_shapeContainer.ScalingResizeBase = value;
			}
		}


		[Category("Shape")]
		[DefaultValue(false)]
		[RefreshProperties( RefreshProperties.Repaint)]
		public bool ScalingResize
		{
			get
			{
				return _shapeContainer.ScalingResize;

			}
			set
			{
				try
				{
					if( _shapeContainer.ScalingResize == value ) return;

			
					_shapeContainer.ScalingResize = value;


					RefreshRegion();
					this.OnScalingResizeChanged( new EventArgs());
					this.Invalidate();
				}
				catch( Exception ex)
				{
					FileWatcher.WriteLine( ex.StackTrace);
				}

			}
		}

		private void RefreshRegion()
		{
			this.Region = null;
			if( this.Shape != null && _clip ) this.Region = this.Shape.GetRegion( true );
			

			ShapeContainer sc = this.Shape as ShapeContainer;
			if( sc != null) 
			{
				sc.PaintClipped = _clip;
				//if(_clip ) sc.Clip = false;//We do not need to clip shape container if this clipped
			}


		}
	
		private bool _clip = false;

		[Category("Shape")]
		[DefaultValue( false)]
		public bool Clip
		{
			get{ return _clip;}
			set
			{
				if( _clip == value) return;
				
				_clip = value;



				RefreshRegion(); 
				this.Invalidate( false );
			}
		}



		
		private RectangleF _oldInvalidatingBounds = RectangleF.Empty;
		private void ShapeContainer_ShapeInternalChanged(object sender, EventArgs e)
		{
			if(_controlInvalidating || this.Shape == null) return;

			try
			{
				RectangleF oldBounds = _oldInvalidatingBounds;
				RectangleF newBounds = this.Shape.InvalidatingBounds;
				Rectangle union = Rectangle.Round( RectangleF.Union( oldBounds, newBounds ));
				this.Invalidate( union );//IN runtime--
				_oldInvalidatingBounds = newBounds;

			}
			catch( Exception ex)
			{
				FileWatcher.WriteLine( ex.StackTrace);
			}
		}

		private void ShapeContainer_ShapePathBoundsChanged(object sender, ValueChangeEventArgs e)
		{

			if( this.Shape != null) RefreshRegion();

			if(_controlInvalidating || this.Shape == null || this.DesignMode ) return;

			try
			{
				RectangleF oldBounds = _oldInvalidatingBounds == RectangleF.Empty ? (RectangleF)e.OldValue : _oldInvalidatingBounds;
				RectangleF newBounds = this.Shape.InvalidatingBounds;

				Rectangle union = Rectangle.Round( RectangleF.Union( oldBounds, newBounds ));
				this.Invalidate( union );//IN runtime--
				_oldInvalidatingBounds = newBounds;

			}
			catch( Exception ex)
			{
				FileWatcher.WriteLine( ex.StackTrace);
			}

		}


		bool _controlInvalidating = false;
		protected override void OnResize(EventArgs e)
		{
			try
			{
				_controlInvalidating = true;
				_shapeContainer.Bounds = this.ClientRectangle;
				base.OnResize (e);
			}
			catch( Exception ex)
			{
				FileWatcher.WriteLine( ex.StackTrace);
			}
			finally
			{
				_controlInvalidating = false;
			}

		}


		[DefaultValue(typeof(Color), "White")]
		[Category("Appearance")]
		public override Color BackColor
		{
			get
			{
				return base.BackColor;
			}
			set
			{
				base.BackColor = value;
			}
		}

		protected override void OnPaint(PaintEventArgs e)
		{
			try
			{
				if( _shape != null) 	
				{
					if( _clip ) e.Graphics.TranslateTransform( -0.5f,-0.5f );
					_shapeContainer.Paint(e.Graphics);
				}
			}
			catch( Exception ex)
			{
				FileWatcher.WriteLine("Shape onpaint failed:"+ ex.Message + "\n" + ex.StackTrace);
			}

			base.OnPaint (e);

		}

	}
}
